#include <time.h>
#include "seqiot.h"
#include "model.h"
#include "sqlite.h"

#define SQL_CHANNEL_COLS "id,name,type,protocol,dev_name,baud,data_bits,parity,stop_bits,gpio,ip_addr,ip_port,timeout"

channel_t *channel_new() {
    channel_t *channel = z_calloc(1, sizeof(channel_t));
    channel->fd = -1;
    return channel;
}

void channel_free(channel_t *channel) {
    if (!channel) return;

    vector_foreach(&channel->devices, (vector_foreach_callback) device_free);
    vector_clear(&channel->devices);

    z_free(channel);
}

void read_row_channel(sqlite3_stmt *stmt, channel_t *rs) {
    int idx = 2;
    read_row_object(stmt, &rs->super);

    rs->type = sqlite3_column_int(stmt, idx++);
    rs->protocol = sqlite3_column_int(stmt, idx++);

    read_row_str(stmt, idx++, rs->serial.device, sizeof(rs->serial.device));
    rs->serial.baud = sqlite3_column_int(stmt, idx++);
    rs->serial.data_bits = sqlite3_column_int(stmt, idx++);
    rs->serial.parity = sqlite3_column_int(stmt, idx++);
    rs->serial.stop_bits = sqlite3_column_int(stmt, idx++);
    rs->serial.gpio = sqlite3_column_int(stmt, idx++);

    read_row_str(stmt, idx++, rs->tcpip.addr, sizeof(rs->tcpip.addr));
    rs->tcpip.port = sqlite3_column_int(stmt, idx++);

    rs->timeout = sqlite3_column_int(stmt, idx++);
}

int _read_stmt_channels(sqlite3 *db, const char *sql, vector_t *channels) {
    int rc;
    sqlite3_stmt *stmt = NULL;

    rc = sqlite3_prepare(db, sql, -1, &stmt, NULL);
    if (SQLITE_OK != rc) {
        sqlite_check(db);
        goto err;
    }

    while (SQLITE_ROW == sqlite3_step(stmt)) {
        channel_t *channel = channel_new();
        read_row_channel(stmt, channel);
        vector_add(channels, channel);
    }

    err:
    sqlite3_finalize(stmt);
    return rc;
}

int read_stmt_channel(sqlite3 *db, vector_t *channels, obj_id id) {
    char sql[1024];
    sprintf(sql, "SELECT %s FROM channel WHERE %s AND id=%d", SQL_CHANNEL_COLS, SQL_DISABLE, id);
    return _read_stmt_channels(db, sql, channels);
}

int read_stmt_channels(sqlite3 *db, vector_t *channels) {
    char sql[1024];
    sprintf(sql, "SELECT %s FROM channel WHERE %s", SQL_CHANNEL_COLS, SQL_DISABLE);
    return _read_stmt_channels(db, sql, channels);
}

/**判断是否在延时范围内，如果是应该跳过不采集*/
_Bool is_retry_sched(device_t *device) {
    time_t curr = time(NULL);

    if (device->_stat.next_sched > curr) {
        struct tm _tm;
        localtime_r(&device->_stat.next_sched, &_tm);

        log_info("device %d/%s will try again at: %02d:%02d:%02d, retries(%d)",
                 device->super.id, device->super.name,
                 _tm.tm_hour, _tm.tm_min, _tm.tm_sec, device->_stat.retries);

        return false;
    } else {
        return true;
    }

    //return device->_stat.next_sched < curr;
}

/**如果采集成功，清除重试标记；否则重试计数，并根据重试次数延时处理后续指令*/
void update_stats(device_t *device, channel_t *channel, int rc) {
    device->_stat.total_messages++;
    channel->_stat.total_messages++;
    if (rc >= 0) {
        device->_stat.retries = 0;
        time(&device->_stat.last_active);
        device->_stat.next_sched = 0;
        device->_stat.successful++;
        channel->_stat.successful++;
    } else {
        device->_stat.retries++;
        device->_stat.failed++;
        channel->_stat.failed++;

        //延时重试
        time(&device->_stat.next_sched);

        if (device->_stat.retries < 5) {
            //5次以内，按传统逻辑处理
        } else if (device->_stat.retries < 10) {
            //10次以内，每1分钟重试一次
            device->_stat.next_sched += (60);
        } else if (device->_stat.retries < 30) {
            //30次以内，每5分钟重试一次
            device->_stat.next_sched += (5 * 60);
        } else {
            //超过30次，每小时重试一次
            device->_stat.next_sched += (60 * 60);
        }
    }
}

time_t next_sched(time_t now, interval_t *interval) {
    if (interval->period > 0) {
        time_t next = now;// - __timezone;
        next -= (next % interval->period);
        next += interval->period;
        next += interval->delay;
        //next += __timezone;

        return next;
    } else {
        return 0;
    }
}
